package com.helei.test;

import java.io.*;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.interfaces.ECPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.ECDSASigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;


public class AppleAuthService {

    public static void main(String[] args) {
        String client_id = "com.mycnbox";
        String keyFilePath = "D:\\Downloads\\AuthKey_Q7643TM8SR.p8";
        String teamId = "C55HN2B5DJ";
        String keyId = " Q7643TM8SR";

        String authorizationCode = "c60a6fbbcc1fe4b70b8833e65c49cee44.0.sywx.FpBswQVGxFvWaeg7NVZkIA"; // 从苹果授权流程中获取的code

        try {
            // 读取苹果.p8私钥
            PrivateKey privateKey = readPrivateKey(keyFilePath);
            // 生成clientSecret
            String clientSecret = generateClientSecret(client_id, teamId, keyId, privateKey);
            System.out.println("Generated Client Secret: " + clientSecret);
            //获取信息
            String userInfo = fetchUserInfo(client_id, clientSecret, authorizationCode);
            if (userInfo != null) {
                decodeIdToken(userInfo);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static PrivateKey readPrivateKey(String keyFilePath) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        FileInputStream fis = new FileInputStream(keyFilePath);
        byte[] keyBytes = new byte[fis.available()];
        fis.read(keyBytes);
        fis.close();

        String keyString = new String(keyBytes);
        keyString = keyString.replace("-----BEGIN PRIVATE KEY-----", "");
        keyString = keyString.replace("-----END PRIVATE KEY-----", "");
        keyString = keyString.replaceAll("\\s", "");

        byte[] decoded = Base64.getDecoder().decode(keyString);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
        KeyFactory kf = KeyFactory.getInstance("EC");
        return kf.generatePrivate(spec);
    }

    public static String generateClientSecret(String client_id, String teamId, String keyId, PrivateKey privateKey) throws JOSEException {
        long now = System.currentTimeMillis() / 1000L;
        long expiration = now + 86400 * 180; // 180 days

        JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                .issuer(teamId)
                .issueTime(new Date(now * 1000))
                .expirationTime(new Date(expiration * 1000))
                .audience("https://appleid.apple.com")
                .subject(client_id)
                .build();

        JWSHeader header = new JWSHeader.Builder(JWSAlgorithm.ES256)
                .keyID(keyId)
                .build();

        SignedJWT signedJWT = new SignedJWT(header, claimsSet);
        JWSSigner signer = new ECDSASigner((ECPrivateKey) privateKey);
        signedJWT.sign(signer);

        return signedJWT.serialize();
    }

    public static String fetchUserInfo(String client_id, String clientSecret, String authorizationCode) throws IOException {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost("https://appleid.apple.com/auth/token");

        String requestBody = String.format(
                "client_id=%s&client_secret=%s&code=%s&grant_type=authorization_code",
                client_id, clientSecret, authorizationCode
        );

        System.out.println("Request Body: " + requestBody);

        httpPost.setEntity(new StringEntity(requestBody));
        httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

        CloseableHttpResponse response = httpClient.execute(httpPost);
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                String responseBody = EntityUtils.toString(response.getEntity());
                System.out.println("User Info: " + responseBody);
                return responseBody;
            } else {
                System.out.println("Failed to get user info from Apple: " + statusCode);
                String responseBody = EntityUtils.toString(response.getEntity());
                System.out.println("Response Body: " + responseBody);
            }
        } finally {
            response.close();
        }
        return null;
    }

    public static JWTClaimsSet decodeIdToken(String userInfo) {
        try {
            String idToken = extractIdTokenFromResponse(userInfo);
            if (idToken != null) {
                SignedJWT signedJWT = SignedJWT.parse(idToken);
                JWTClaimsSet claimsSet = signedJWT.getJWTClaimsSet();
                System.out.println("Decoded ID Token Claims:");
                System.out.println("Issuer: " + claimsSet.getIssuer());
                System.out.println("Subject: " + claimsSet.getSubject());
                System.out.println("Audience: " + claimsSet.getAudience());
                System.out.println("Expiration Time: " + claimsSet.getExpirationTime());
                System.out.println("Issue Time: " + claimsSet.getIssueTime());
                System.out.println("Email: " + claimsSet.getStringClaim("email"));
                System.out.println("Email Verified: " + claimsSet.getBooleanClaim("email_verified"));
                return claimsSet;
            } else {
                System.out.println("ID Token not found in the response.");
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String extractIdTokenFromResponse(String response) {
        String[] parts = response.split(",");
        for (String part : parts) {
            if (part.contains("id_token")) {
                return part.split(":")[1].replace("\"", "").trim();
            }
        }
        return null;
    }
}
